﻿using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Tinter.Models;
using Tinter.Infrastructure.Data.UnitOfWork;

namespace Tinter.Infrastructure.Data
{
    /// <summary>
    /// Represents the repository base class.
    /// </summary>
    /// <typeparam name="TEntity">The type of underlying entity in this repository</typeparam>
    public class Repository<TEntity> : IRepository<TEntity> where TEntity : EntityBase
    {
        #region Members

        private readonly IQueryableUnitOfWork unitOfWork;

        #endregion

        #region Constructors

        /// <summary>
        /// Create a new instance of repository with specified data context.
        /// </summary>
        /// <param name="unitOfWork">Associated Unit Of Work</param>
        public Repository(IQueryableUnitOfWork unitOfWork)
        {
            if (unitOfWork == null)
            {
                throw new ArgumentNullException(MethodBase.GetCurrentMethod().GetParameters()[0].Name);
            }

            this.unitOfWork = unitOfWork;
        }

        #endregion

        #region IRepository Members

        public IDataContext DataContext
        {
            get
            {
                return unitOfWork;
            }
        }

        public virtual void Add(TEntity item)
        {
            if (item != null)
            {
                unitOfWork.GetSet<TEntity>().Add(item);
            }
            else
            {
                //LoggerFactory.CreateLog()
                //          .LogInfo(Messages.info_CannotAddNullEntity, typeof(TEntity).ToString());

            }
        }

        public virtual void Delete(TEntity item)
        {
            if (item != null)
            {
                unitOfWork.GetSet<TEntity>().Remove(item);
            }
            else
            {
                //LoggerFactory.CreateLog()
                //          .LogInfo(Messages.info_CannotRemoveNullEntity, typeof(TEntity).ToString());
            }
        }

        public virtual void Track(TEntity item)
        {
            if (item != null)
            {
                unitOfWork.Attach(item);
            }
            else
            {
                //LoggerFactory.CreateLog()
                //          .LogInfo(Messages.info_CannotRemoveNullEntity, typeof(TEntity).ToString());
            }
        }

        public virtual TEntity Get(object id)
        {
            if (id != null)
            {
                return unitOfWork.GetSet<TEntity>().Find(id);
            }

            return null;
        }

        public virtual IQueryable<TEntity> All()
        {
            return unitOfWork.GetSet<TEntity>().AsQueryable();
        }

        public virtual IQueryable<TEntity> GetPaged<TProperty>(int pageIndex, int pageCount, Expression<Func<TEntity, TProperty>> orderByExpression, bool ascending)
        {
            var set = unitOfWork.GetSet<TEntity>();

            var list = ascending ? set.OrderBy(orderByExpression) : set.OrderByDescending(orderByExpression);

            return list.Skip(pageCount * pageIndex)
                          .Take(pageCount)
                          .AsQueryable();
        }

        public virtual IQueryable<TEntity> GetFiltered(Expression<Func<TEntity, bool>> filter)
        {
            return unitOfWork.GetSet<TEntity>().Where(filter).AsQueryable();
        }

        #endregion
    }
}
